package com.lyeducation.security.config;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lyeducation.controllers.dto.system.LoginUserDto;
import com.lyeducation.core.base.LOGINSAVEUSERTYPE;
import com.lyeducation.core.base.SysConstants;
import com.lyeducation.util.StringUtils;
import com.lyeducation.util.jwt.JwtUtil;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

// 继承重写获取username方法加上headerToken
public class AuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
  //  public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
  public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
  public static final String SPRING_SECURITY_FORM_LOGIN_TYPE = "loginType";
  private JwtUtil jwtUtil;
  private String usernameParameter = "username";
  private String passwordParameter = "password";
  private boolean postOnly = true;

  public AuthenticationProcessingFilter(String signInProcessingUrl) {
    //    "/是必须加的"
    super(new AntPathRequestMatcher(signInProcessingUrl, "POST"));
  }

  @Override
  public Authentication attemptAuthentication(
      HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    if (this.postOnly && !"POST".equals(request.getMethod())) {
      throw new AuthenticationServiceException(
          "Authentication method not supported: " + request.getMethod());
    } else {
      // attempt Authentication when Content-Type is json

      //      String username = this.obtainUsername(request);
      //      String password = this.obtainPassword(request);
      //      if (username == null) {
      //        username = "";
      //      }
      //
      //      if (password == null) {
      //        password = "";
      //      }
      //
      //      username = username.trim();requestURL
      //      UsernamePasswordAuthenticationToken authRequest =
      //          new UsernamePasswordAuthenticationToken(username, password);
      //      this.setDetails(request, authRequest);
      //      return this.getAuthenticationManager().authenticate(authRequest);
      return createAuthenticationByLoginFormOrJson(request);
    }
  }

  protected Authentication createAuthenticationByLoginFormOrJson(HttpServletRequest request) {
    String loginType = null;
    String username = null;
    String password = null;
    Map<String, String> loginMap = new HashMap<String, String>(3);
    if (request.getContentType().equals(MediaType.APPLICATION_JSON_UTF8_VALUE)
            || request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
      // use jackson to deserialize json
      ObjectMapper mapper = new ObjectMapper();
      LoginUserDto loginUserDto = null;
      try (InputStream is = request.getInputStream()) {
        loginUserDto = mapper.readValue(is, LoginUserDto.class);
      } catch (IOException e) {
        e.printStackTrace();
      }
      loginType = loginUserDto.getLoginType();
      username = loginUserDto.getUsername();
      password = loginUserDto.getPassword();
    } else {
      loginType =
              request.getParameter(AuthenticationProcessingFilter.SPRING_SECURITY_FORM_LOGIN_TYPE);
      username = request.getParameter(this.usernameParameter);
      password = request.getParameter(this.passwordParameter);
    }
    loginType = StringUtils.trim(loginType);
    loginMap.put(SysConstants.USERNAME.getValue(), username);
    if (StringUtils.isNotBlank(loginType)) {
      loginMap.put(AuthenticationProcessingFilter.SPRING_SECURITY_FORM_LOGIN_TYPE, loginType);
      if (StringUtils.equals(
              loginType, String.valueOf(LOGINSAVEUSERTYPE.LOGIN_USER_BY_MOBILE_CODE.ordinal()))) {
        loginMap.put(AuthenticationProcessingFilter.SPRING_SECURITY_FORM_PASSWORD_KEY, password);
      }

    }
//    else {
//      String jwtToken = jwtUtil.getJwtTokenByRequestHeader(request);
//      if (jwtToken != null) {
//        loginMap.put(JwttokenconfigEnum.jwtToken.getValue(), jwtToken);
//      }
//    }
    String loginJsonString = JSON.toJSONString(loginMap);
    if (loginJsonString == null) {
      loginJsonString = "";
    }
    if (password == null) {
      password = "";
    }
    UsernamePasswordAuthenticationToken authRequest =
            new UsernamePasswordAuthenticationToken(loginJsonString, password);
    this.setDetails(request, authRequest);
    return this.getAuthenticationManager().authenticate(authRequest);
  }

  protected void setDetails(
      HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
    authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
  }

  public void setPostOnly(boolean postOnly) {
    this.postOnly = postOnly;
  }

  public final String getUsernameParameter() {
    return this.usernameParameter;
  }

  public void setUsernameParameter(String usernameParameter) {
    Assert.hasText(usernameParameter, "Username parameter must not be empty or null");
    this.usernameParameter = usernameParameter;
  }

  public final String getPasswordParameter() {
    return this.passwordParameter;
  }

  public void setPasswordParameter(String passwordParameter) {
    Assert.hasText(passwordParameter, "Password parameter must not be empty or null");
    this.passwordParameter = passwordParameter;
  }

  public void setJwtUtil(JwtUtil jwtUtil) {
    this.jwtUtil = jwtUtil;
  }
}
